package model;

import java.sql.SQLException;
import java.util.ArrayList;

/**
 * Diese Klasse stellt eine Organisationsebene dar. (z.B. Modul, Fach)
 * 
 * @author David
 * 
 */
public class Ebene {
	public static final int ZUSTAND_UNBEARBEITET = 0;
	public static final int ZUSTAND_GEAENDERT = 1;
	public static final int ZUSTAND_AKZEPTIERT_REDAKT = 2;
	public static final int ZUSTAND_AKZEPTIERT_DEZ2 = 3;
	public static final int ZUSTAND_AKZEPTIERT_BEIDE = 4;

	private int id;
	private String name;
	private int prosaId;
	private Feld prosa;
	private long erstellungszeit;
	private int redaktionszustand;

	private String verantwortlichIds;
	private Benutzer[] verantwortlich;
	private String redakteurIds;
	private Benutzer[] redakteur;
	private String unterelementIds;
	private Ebene[] unterelement;
	private String feldIds;
	private Feld[] feld;

	private EbenenRepository ebenenRepository;
	private BenutzerRepository benutzerRepository;
	private FelderRepository felderRepository;

	/**
	 * Erstellt eine neue Ebeneninstanz. (Nur für Änderungen benutzen. Für ganz
	 * neue Ebenen das EbenenRepository benutzen!)
	 * 
	 * @param id
	 *            die ID
	 * @param name
	 *            der Name
	 * @param prosaId
	 *            die ProsaID
	 * @param erstellungszeit
	 *            die Erstellungszeit
	 * @param redaktionszustand
	 *            der Redaktionszustand
	 * @param verantwortlichIds
	 *            die IDs der Verantwortlichen
	 * @param redakteurIds
	 *            die IDs der Redakteure
	 * @param unterelementIds
	 *            die IDs der Unterelemente
	 * @param feldIds
	 *            die IDs der Felder
	 */
	public Ebene(int id, String name, int prosaId,
			long erstellungszeit, int redaktionszustand,
			String verantwortlichIds, String redakteurIds,
			String unterelementIds, String feldIds) {
		this.id = id;
		this.name = name;
		this.prosaId = prosaId;
		this.erstellungszeit = erstellungszeit;
		this.redaktionszustand = redaktionszustand;
		this.verantwortlichIds = verantwortlichIds;
		this.unterelementIds = unterelementIds;
		this.redakteurIds = redakteurIds;
		this.feldIds = feldIds;
		feld = null;
	}

	/**
	 * Gibt die ID zurück.
	 * 
	 * @return die ID
	 */
	public int getId() {
		return id;
	}

	/**
	 * Gibt das Prosafeld zurück.
	 * 
	 * @return das Prosafeld
	 * @throws SQLException
	 * @throws ClassNotFoundException
	 */
	public Feld getProsa() throws ClassNotFoundException, SQLException {
		if (prosa == null) {
			if (felderRepository == null) {
				felderRepository = FelderRepository.getInstance();
			}
			if (prosaId != 0) {
				Feld[] tmp = felderRepository.getFeldNachId(prosaId);
				if (tmp != null) {
					for (int i = 0; i < tmp.length; i++) {
						if (tmp[i].getAenderung() == erstellungszeit) {
							prosa = tmp[i];
							break;
						}
					}
				}
			}
		}

		return prosa;
	}

	/**
	 * Gibt den Namen zurück.
	 * 
	 * @return der Name
	 */
	public String getName() {
		return name;
	}

	/**
	 * Gibt die Prosa-ID zurück.
	 * 
	 * @return die Prosa-ID
	 */
	public int getProsaId() {
		return prosaId;
	}

	/**
	 * Gibt das Erstellungsdatum zurück.
	 * 
	 * @return die Erstellungszeit
	 */
	public long getErstellungszeit() {
		return erstellungszeit;
	}

	/**
	 * Gibt den Redaktionszustand zurück.
	 * 
	 * @return der Redaktionszustand
	 */
	public int getRedaktionszustand() {
		return redaktionszustand;
	}
	
	/**
	 * Gibt die FelderIDs als String zurück zurück.
	 * 
	 * @return der FelderIDs
	 */
	public String getFeldIds() {
		return feldIds;
	}
	
	/**
	 * Setzt den Redaktionszustand
	 * 
	 * @param redaktionszustandNeu
	 *            der neue Redaktionszustand
	 * @throws IllegalArgumentException
	 * @throws SQLException
	 * @throws ClassNotFoundException
	 */
	public void setRedaktionszustand(int redaktionszustandNeu)
			throws IllegalArgumentException, SQLException,
			ClassNotFoundException {
		if (redaktionszustandNeu != redaktionszustand) {
			// DB Update
			DatenbankSchnittstelle dbs = DatenbankSchnittstelle.getInstance();
			String[][] db_werte = new String[2][1];
			// spaltennamen
			db_werte[0][0] = "redaktionszustand";
			// werte
			db_werte[1][0] = "" + redaktionszustandNeu;
			dbs.update("ebene", "id=" + this.id + " AND erstellungszeit="+ this.erstellungszeit, db_werte);
			// Objekt updaten
			redaktionszustand = redaktionszustandNeu;
		}
	}
	
	
	/**
	 * Prüft
	 * 
	 * @return <code>true</code>, wenn die Ebene im Ebenenbaum vorhanden ist,
	 *         ansonsten <code>false</code>
	 * @throws ClassNotFoundException
	 * @throws SQLException
	 */
	public boolean istGeloescht() throws ClassNotFoundException, SQLException {
		if (ebenenRepository == null) {
			ebenenRepository = EbenenRepository.getInstance();
		}
		if(id == 1) {
			return false;
		}
		return !haengtAnEbene(ebenenRepository.getNeusteEbeneNachId(1));
	}

	/**
	 * Prüft rekursiv, ob eine Ebene an einer anderen hängt.
	 * 
	 * @param e
	 *            die zu prüfende Ebene
	 * @return <code>true</code>, wenn die Ebene an der übergebenen Ebene hängt,
	 *         ansonsten <code>false</code>
	 * @throws ClassNotFoundException
	 * @throws SQLException
	 */
	boolean haengtAnEbene(Ebene e) throws ClassNotFoundException,
			SQLException {
		if (e != null) {
			Ebene[] unterebenen = e.getUnterelement();
			if (unterebenen != null) {
				for (int i = 0; i < unterebenen.length; i++) {
					if (this == unterebenen[i]) { // Prüfen hängt diese Ebene direkt an unterebene[i]
						return true;
					} else if (haengtAnEbene(unterebenen[i])) { // wenn nicht dann Rekursionsschritt: hängt diese Ebene weiter unten an unterebene[i]
						return true;
					}
				}
			}
		}
		return false;
	}

	/**
	 * gibt die verantwortlichen zurück.
	 * 
	 * @return die Verantwortlichen als Benutzerarray
	 * @throws ClassNotFoundException
	 * @throws SQLException
	 */
	public Benutzer[] getVerantwortlich() throws ClassNotFoundException,
			SQLException {
		if (verantwortlich == null) { // array entweder leer oder nocht nicht geladen -> probieren zu laden
			if (benutzerRepository == null) {
				benutzerRepository = BenutzerRepository.getInstance();
			}
			if (!verantwortlichIds.equals("")) {
				String[] temp = verantwortlichIds.split(";");
				ArrayList<Benutzer> benutzerarray = new ArrayList<Benutzer>();
				for (int i = 0; i < temp.length; i++) {
					if (benutzerRepository.getBenutzerNachId(Integer.parseInt(temp[i])) != null) {
						benutzerarray.add(benutzerRepository.getBenutzerNachId(Integer.parseInt(temp[i])));
					}
				}
				if (benutzerarray.size() > 0) {
					benutzerarray.trimToSize();
					verantwortlich = benutzerarray.toArray(new Benutzer[0]);
				} else {
					verantwortlich = null;
				}
			}
		} else { // Aktualisieren
			ArrayList<Benutzer> benutzerarray = new ArrayList<Benutzer>();
			for (int i = 0; i < verantwortlich.length; i++) {
				if (benutzerRepository.getBenutzerNachId(verantwortlich[i].getId()) != null) {
					benutzerarray.add(benutzerRepository.getBenutzerNachId(verantwortlich[i].getId()));
				}
			}
			if (benutzerarray.size() > 0) {
				benutzerarray.trimToSize();
				verantwortlich = benutzerarray.toArray(new Benutzer[0]);
			} else {
				verantwortlich = null;
			}
		}
		return verantwortlich;
	}

	/**
	 * Setzt die Verantwortlichen.
	 * 
	 * @param verantwortlichNeu
	 *            die Verantwortlichen
	 * @throws ClassNotFoundException
	 * @throws SQLException
	 */
	public void setVerantwortlich(Benutzer[] verantwortlichNeu)
			throws ClassNotFoundException, SQLException {
		// DB Update
		DatenbankSchnittstelle dbs = DatenbankSchnittstelle.getInstance();
		String[][] db_werte = new String[2][1];
		// spaltennamen
		db_werte[0][0] = "verantwortlichIds";
		// werte
		db_werte[1][0] = "";
		if (verantwortlichNeu != null) {
			for (int i = 0; i < verantwortlichNeu.length; i++) {
				if (verantwortlichNeu[i] != null) {
					db_werte[1][0] += verantwortlichNeu[i].getId() + ";";
				}
			}
			if (db_werte[1][0].endsWith(";")) {
				db_werte[1][0] = db_werte[1][0].substring(0,
						db_werte[1][0].length() - 1);
			}
		}
		dbs.update("ebene", "id=" + this.id + " AND erstellungszeit=" + this.erstellungszeit, db_werte);
		// Array Updaten
		if (verantwortlichNeu != null) {
			if (verantwortlichNeu.length > 0) {
				verantwortlich = verantwortlichNeu;
			} else {
				verantwortlich = null;
			}
		} else {
			verantwortlich = null;
		}
	}

	/**
	 * Gibt die Redakteure zurück.
	 * 
	 * @return die Redakteure als Benutzerarray
	 * @throws ClassNotFoundException
	 * @throws SQLException
	 */
	public Benutzer[] getRedakteur() throws ClassNotFoundException,
			SQLException {
		if (redakteur == null) { // array entweder leer oder nocht nicht geladen -> probieren zu laden
			if (benutzerRepository == null) {
				benutzerRepository = BenutzerRepository.getInstance();
			}
			if (!redakteurIds.equals("")) {
				String[] temp = redakteurIds.split(";");
				ArrayList<Benutzer> benutzerarray = new ArrayList<Benutzer>();
				for (int i = 0; i < temp.length; i++) {
					if (benutzerRepository.getBenutzerNachId(Integer.parseInt(temp[i])) != null) {
						benutzerarray.add(benutzerRepository.getBenutzerNachId(Integer.parseInt(temp[i])));
					}
				}
				if (benutzerarray.size() > 0) {
					benutzerarray.trimToSize();
					redakteur = benutzerarray.toArray(new Benutzer[0]);
				} else {
					redakteur = null;
				}
			}
		} else { // Aktualisieren
			ArrayList<Benutzer> benutzerarray = new ArrayList<Benutzer>();
			for (int i = 0; i < redakteur.length; i++) {
				if (redakteur[i] != null && benutzerRepository.getBenutzerNachId(redakteur[i].getId()) != null) {
					benutzerarray.add(benutzerRepository
							.getBenutzerNachId(redakteur[i].getId()));
				}
			}
			if (benutzerarray.size() > 0) {
				benutzerarray.trimToSize();
				redakteur = benutzerarray.toArray(new Benutzer[0]);
			} else {
				redakteur = null;
			}
		}
		return redakteur;
	}

	/**
	 * Setzt die Redakteure.
	 * 
	 * @param redakteurNeu
	 *            die Redakteure als Benutzer-Array
	 * @throws ClassNotFoundException
	 * @throws SQLException
	 */
	public void setRedakteur(Benutzer[] redakteurNeu) throws ClassNotFoundException, SQLException {
		// DB Update
		DatenbankSchnittstelle dbs = DatenbankSchnittstelle.getInstance();
		String[][] db_werte = new String[2][1];
		// spaltennamen
		db_werte[0][0] = "redakteurIds";
		// werte
		db_werte[1][0] = "";
		if (redakteurNeu != null) {
			for (int i = 0; i < redakteurNeu.length; i++) {
				if (redakteurNeu[i] != null) {
					db_werte[1][0] += redakteurNeu[i].getId() + ";";
				}
			}
			if (db_werte[1][0].endsWith(";")) {
				db_werte[1][0] = db_werte[1][0].substring(0,
						db_werte[1][0].length() - 1);
			}
		}
		dbs.update("ebene", "id=" + this.id + " AND erstellungszeit="
				+ this.erstellungszeit, db_werte);
		// Array Updaten
		if (redakteurNeu != null) {
			if (redakteurNeu.length > 0) {
				redakteur = redakteurNeu;
			} else {
				redakteur = null;
			}
		} else {
			redakteur = null;
		}
	}

	/**
	 * Gibt die Unterelemente zurück.
	 * 
	 * @return die Unterelemente als Ebenen-Array
	 * @throws ClassNotFoundException
	 * @throws SQLException
	 */
	public Ebene[] getUnterelement() throws ClassNotFoundException,
			SQLException {
		if (unterelement == null) { // array entweder leer oder nocht nicht geladen -> probieren zu laden
			if (ebenenRepository == null) {
				ebenenRepository = EbenenRepository.getInstance();
			}
			if (!unterelementIds.equals("")) {
				String[] temp = unterelementIds.split(";");
				ArrayList<Ebene> ebenenarray = new ArrayList<Ebene>();
				for (int i = 0; i < temp.length; i++) {
					if(!temp[i].equals("")) {
						if(ebenenRepository.getNeusteEbeneNachId(Integer.parseInt(temp[i])) != null) {
							ebenenarray.add(ebenenRepository.getNeusteEbeneNachId(Integer.parseInt(temp[i])));
						}
					}
				}
				if (ebenenarray.size() > 0) {
					ebenenarray.trimToSize();
					unterelement = ebenenarray.toArray(new Ebene[0]);
				} else {
					unterelement = null;
				}
			}

		} else { // Versionen aktualisieren
			if (ebenenRepository == null) {
				ebenenRepository = EbenenRepository.getInstance();
			}
			ArrayList<Ebene> ebenenarray = new ArrayList<Ebene>();
			for (int i = 0; i < unterelement.length; i++) {
				if (unterelement[i] != null) {
					if (ebenenRepository.getNeusteEbeneNachId(unterelement[i].getId()) != null) {
						ebenenarray.add(ebenenRepository.getNeusteEbeneNachId(unterelement[i].getId()));
					}
				}
			}
			if (ebenenarray.size() > 0) {
				ebenenarray.trimToSize();
				unterelement = ebenenarray.toArray(new Ebene[0]);
			} else {
				unterelement = null;
			}
		}

		return unterelement;
	}

	/**
	 * Gibt die Felder zurück.
	 * 
	 * @return die Felder als Feld-Array
	 * @throws ClassNotFoundException
	 * @throws SQLException
	 */
	public Feld[] getFeld() throws ClassNotFoundException, SQLException {
		if (felderRepository == null) {
			felderRepository = FelderRepository.getInstance();
		}
		if (feld == null) { // array entweder leer oder nocht nicht geladen -> probieren zu laden
			if (!feldIds.equals("")) {
				String[] ids = feldIds.split(";");
				ArrayList<Feld> feldarray = new ArrayList<Feld>();
				Feld[] feldTmp;
				for (int i = 0; i < ids.length; i++) {
					feldTmp = felderRepository.getFeldNachId(Integer.parseInt(ids[i]));
					if (feldTmp != null) {
						for (int j = 0; j < feldTmp.length; j++) {
							if (feldTmp[j].getAenderung() == erstellungszeit) {
								feldarray.add(feldTmp[j]);
								break;
							}
						}
					}
				}
				if (feldarray.size() > 0) {
					feldarray.trimToSize();
					feld = feldarray.toArray(new Feld[0]);
					
				} else {
					feld = null;
				}
			}
		} else { // Versionen aktualisieren
			ArrayList<Feld> feldarray = new ArrayList<Feld>();
			Feld[] feldTmp;
			for (int i = 0; i < feld.length; i++) {
				feldTmp = felderRepository.getFeldNachId(feld[i].getId());
				if (feldTmp != null) {
					for (int j = 0; j < feldTmp.length; j++) {
						if (feldTmp[j].getAenderung() == erstellungszeit) {
							feldarray.add(feldTmp[j]);
							break;
						}
					}
				}
			}
			if (feldarray.size() > 0) {
				feldarray.trimToSize();
				feld = feldarray.toArray(new Feld[0]);
			} else {
				feld = null;
			}
		}
		return feld;
	}
	
	
	/**
	 * Liefert die Überebenen einer Ebene innerhalb des Baumes an "Ebene aktuell".
	 * Tipp: aufrufen mit baum = Rootebene (ID: 1)
	 * @param baum Der Baum in dem die Überebenen gesucht werden. Am besten mit der Rootebene (ID: 1) aufrufen. (Die Variable Baum ist eigentlich nur für die Rekursion wichtig)
	 * @return ebenen Die Überebenen deiser Ebene
	 * @throws ClassNotFoundException
	 * @throws SQLException
	 */
	public Ebene[] ueberEbenenFindenAn(Ebene baum) throws ClassNotFoundException, SQLException {
		return ebenenRepository.ueberEbenenFinden(this, baum);
	}
}
